#ifndef HANDLEMANAGER_H
#define HANDLEMANAGER_H


#include <cassert>
#include <vector>


template <typename TAG>
class cHandle
{
	union
	{
		enum
		{
			// sizes to use for bit fields
			MAX_BITS_INDEX = 16,
			MAX_BITS_MAGIC = 16,

			// sizes to compare against for asserting dereferences
			MAX_INDEX = ( 1 << MAX_BITS_INDEX) - 1,
			MAX_MAGIC = ( 1 << MAX_BITS_MAGIC) - 1,
		};

		struct
		{
			unsigned m_Index : MAX_BITS_INDEX;  // index into resource array
			unsigned m_Magic : MAX_BITS_MAGIC;  // magic number to check
		};

		unsigned int m_Handle;
	};


public:

	cHandle() 
		: m_Handle(0) {}

		void Init( unsigned int index );


		unsigned int GetIndex ( void ) const  {  return (  m_Index  );  }
		unsigned int GetMagic ( void ) const  {  return (  m_Magic  );  }
		unsigned int GetHandle( void ) const  {  return (  m_Handle );  }
		bool         IsNull   ( void ) const  {  return ( !m_Handle );  }

		operator unsigned int ( void ) const  {  return (  m_Handle );  }

};



template <typename TAG>
void cHandle<TAG>::Init( unsigned int index )
{
	assert( IsNull() );             // don't allow reassignment
	assert( index <= MAX_INDEX );   // verify range

	static unsigned int s_AutoMagic = 0;
	if ( ++s_AutoMagic > MAX_MAGIC )
	{
		s_AutoMagic = 1;    // 0 is used for "null handle"
	}

	m_Index = index;
	m_Magic = s_AutoMagic;
}


template <typename TAG>
inline bool operator != ( cHandle <TAG> l, cHandle <TAG> r )
{  return ( l.GetHandle() != r.GetHandle() );  }

template <typename TAG>
inline bool operator == ( cHandle <TAG> l, cHandle <TAG> r )
{  return ( l.GetHandle() == r.GetHandle() );  }




/************************************************************************/
/* the handle manager
/*
/*
/************************************************************************/
template <typename DATA, typename HANDLE>
class cHandleManager
{
private:
	// typedef std::vector <DATA>         UserVec;
	typedef std::vector <DATA*>         UserVec;
	typedef std::vector <unsigned int> MagicVec;
	typedef std::vector <unsigned int> RefCountVec;
	typedef std::vector <unsigned int> FreeVec;

	UserVec  m_UserData;     // data we're going to get to
	MagicVec m_MagicNumbers; // corresponding magic numbers
	FreeVec  m_FreeSlots;    // keeps track of free slots in the db
	RefCountVec m_RefCount;	 // keep track of how many request are there for each handle	

public:
	
	~cHandleManager();

	// acquisition
	DATA* Acquire( HANDLE& handle );
	void  Release( HANDLE  handle );

	// dereferencing
	DATA*       Dereference( HANDLE handle );
	const DATA* Dereference( HANDLE handle ) const;

	// other query
	unsigned int GetUsedHandleCount( void ) const
	{  return ( m_MagicNumbers.size() - m_FreeSlots.size() );  }
	bool HasUsedHandles( void ) const
	{  return ( !!GetUsedHandleCount() );  }

	unsigned int GetRefCount(HANDLE handle)
	{	return m_RefCount[handle.GetIndex()];	}

};


template <typename DATA, typename HANDLE>
cHandleManager<DATA,HANDLE>::~cHandleManager()
{
	// delete all pointers
	UserVec::iterator iter = m_UserData.begin();
	while ( iter!=m_UserData.end() )
	{	
		delete (*iter);	
		iter++;
	}
	m_UserData.clear();
}


template <typename DATA, typename HANDLE>
DATA* cHandleManager<DATA,HANDLE>::Acquire( HANDLE& handle )
{
	assert( m_RefCount.size()==m_MagicNumbers.size() );
	// if such a handle exists, increase its ref count 
	// and return its associated data
	if (m_MagicNumbers.size()>0 && 
		m_MagicNumbers[handle.GetIndex()] == handle.GetMagic())
	{
		// there is already such a handle
		assert(m_RefCount[handle.GetIndex()]>0);	
		m_RefCount[handle.GetIndex()]++;
		return m_UserData[handle.GetIndex()];
	}
		
	// not such a handle, continue...

	// if free list is empty, add a new one otherwise 
	// use first one found
	unsigned int index;
	if (m_FreeSlots.empty())
	{
		index = (unsigned int)m_MagicNumbers.size();
		handle.Init(index);
		m_UserData.push_back( new DATA() );
		m_MagicNumbers.push_back( handle.GetMagic() );
		m_RefCount.push_back(1);
	}
	else
	{
		index = m_FreeSlots.back();
		handle.Init(index);
		m_FreeSlots.pop_back();
		m_MagicNumbers[index] = handle.GetMagic();
		m_RefCount[index]=1;
	}

	return m_UserData[index];
}



template <typename DATA, typename HANDLE>
void cHandleManager<DATA,HANDLE>::Release( HANDLE handle )
{
	// which one?
	unsigned int index = handle.GetIndex();

	// make sure it's valid
	assert( index < m_UserData.size() );
	assert( m_MagicNumbers[ index ] == handle.GetMagic() );
	assert( m_MagicNumbers.size()==m_RefCount.size());


	// decrease its ref count
	m_RefCount[index]--;

	if( m_RefCount[index]==0 )
	{
		// ok remove it - tag as unused and add to free list
		m_MagicNumbers[ index ] = 0;
		m_FreeSlots.push_back( index );		
	}
}


template <typename DATA, typename HANDLE>
inline DATA* cHandleManager<DATA,HANDLE>::Dereference( HANDLE handle )
{
	if (handle.IsNull())
		return 0;

	// check handle validity - $ this check can be removed for speed
	// if you can assume all handle references are always valid.
	unsigned int index = handle.GetIndex();
	if (GetRefCount(handle)==0)
	{
		return 0;	
	}

	if (   ( index >= m_UserData.size() )
		|| ( m_MagicNumbers[ index ] != handle.GetMagic() ) )
	{
		// no good! invalid handle == client programming error
		assert( 0 );
		return ( 0 );
	}

	return m_UserData[index];
}


template <typename DATA, typename HANDLE>
inline const DATA* cHandleManager<DATA, HANDLE>::Dereference( HANDLE handle ) const
{
	// this lazy cast is ok - non-const version does not modify anything
	typedef cHandleManager<DATA, HANDLE> ThisType;
	return ( const_cast <ThisType*> ( this )->Dereference( handle ) );
}




#endif